/**
 * com.pas.iam.account.resource.NewJDialog.java
 * Copyright (c) 2009 Pas corporation All Rights Reserved.
 */
package com.web.server.common.dao;

import java.util.Collection;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

/**
 * 分页查询工具。 根据查询hql语句将查询结果返回。
 * 
 * @author  刘红军
 * @version Ver 1.0 2008-03-06 新建
 * @since   PASIAM Ver1.0
 */
public class PageUtil
{

    /**
     * 查询结果的总记录数
     * 
     * @since Ver1.0
     */
    private int count = 0;

    /**
     * 数据库连接工厂
     * 
     * @since Ver1.0
     */
    private SessionFactory sessionFactory = null;

    /**
     * 查询出指定页的记录集合。 
     * <p>
     * 使用hibernate提供的方法对类级别的对象进行添加、修改。
     * 
     * @param  hql 查询所有的hql语句
     * @param  pageListData 分页类
     * @return List 指定页的记录集
     * @author 刘红军
     * @since  PASIAM Ver1.0
     */
    public List queryByPage(String hql, PageListData pageListData)
    {

        // 在pageListData中取得页码
        int page = pageListData.getPageNeeded();

        // 在pageListData中取得每页记录条数
        int pageSize = pageListData.getPageSize();

        // 在SessionFactory中获得Session
        Session session = sessionFactory.openSession();

        // 组装查询总记录数hql
        int sqlFrom = hql.indexOf("from");
        int sqlGroupby = hql.indexOf("group by");
        int sqlOrderby = hql.indexOf("order by");
        boolean isContainDistinct = hql.contains("distinct");
        String countHql = "";

        // 创建count() Query对象
        Query countQuery = null;
        
        // 创建list Query对象
        Query query = session.createQuery(hql);
        
        // 如果查询条件中不包含distinct关键字，化查询语句得到总的记录行数，否则只能直接查询
        if(!isContainDistinct)
        {
            // 因为此方法只取得查询的结果总数，所以将查询语句中可能存在的排序语句去掉来提高查询效率
            if (sqlGroupby > 0)
            {
                countHql = "select count(count(*)) " + hql.substring(sqlFrom, sqlOrderby);
            } else if (sqlOrderby > 0)
            {
                countHql = "select count(*) " + hql.substring(sqlFrom, sqlOrderby);
            } else
            {
                countHql = "select count(*) " + hql.substring(sqlFrom);
            }

            countQuery = session.createQuery(countHql);
            
            // 取得所有记录条数
            this.setCount(((Number) countQuery.list().get(0)).intValue());
        }else
        {
           countQuery = session.createQuery(hql);
            
            // 执行查询
            List list = countQuery.list();
            
            // 取得所有记录条数
            this.setCount(list.size());
        }

        // 设置记录开始位置
        query.setFirstResult((page - 1) * pageSize);

        // 设置查询记录条数
        query.setMaxResults(pageSize);
        
        // 执行查询
        List list = query.list();

        // 关闭Session
        session.close();

        // 返回查询结果
        return list;
    }

    /**
     * 参数分页查询
     * <p>
     * 使用hibernate提供的方法根据查询语句和参数，查询出实体对象组合结果集。
     * 
     * @param  hql 需要执行的hql语句。
     * @return List 查询出来的实体对象组合结果集对象，包含了分页信息。
     * @author 刘红军
     * @since  PASIAM Ver1.0
     */
    public List queryByPageParams(final String hql,
            final PageListData pageListData, final String[] paramNames,
            final Object[] values)
    {
        // 在pageListData中取得页码
        int page = pageListData.getPageNeeded();

        // 在pageListData中取得每页记录条数
        int pageSize = pageListData.getPageSize();

        // 在SessionFactory中获得Session
        Session session = sessionFactory.openSession();

        // 组装查询总记录数hql
        int sqlFrom = hql.indexOf("from");
        int sqlGroupby = hql.indexOf("group by");
        int sqlOrderby = hql.indexOf("order by");
        boolean isContainDistinct = hql.contains("distinct");        
        String countHql = "";
        
        // 设置查询参数的值
        Query countQuery = null;
        Query query = session.createQuery(hql);
        
        // 如果查询条件中不包含distinct关键字，化查询语句得到总的记录行数，否则只能直接查询
        if(!isContainDistinct)
        {            
            // 因为此方法只取得查询的结果总数，所以将查询语句中可能存在的排序语句去掉来提高查询效率
            if (sqlGroupby > 0)            {
                countHql = "select count(count(*)) "
                        + hql.substring(sqlFrom, sqlOrderby);
            } else if (sqlOrderby > 0)
            {
                countHql = "select count(*) " + hql.substring(sqlFrom, sqlOrderby);
            } else
            {
                countHql = "select count(*) " + hql.substring(sqlFrom);
            }
            countQuery = session.createQuery(countHql);
        }else
        {
            countQuery = session.createQuery(hql);
        }
        
        // 设置参数值
        if (values != null)
        {
            for (int i = 0; i < values.length; i++)
            {
                // 如果参数是集合
                if (values[i] instanceof Collection)
                {
                    countQuery.setParameterList(paramNames[i],
                            (Collection) values[i]);
                    query.setParameterList(paramNames[i],
                            (Collection) values[i]);
                } else if (values[i] instanceof Object[]) // 如果参数是数组
                {
                    countQuery.setParameterList(paramNames[i],
                            (Object[]) values[i]);
                    query.setParameterList(paramNames[i], (Object[]) values[i]);
                } else
                    
                // 如果参数是单个对象
                {
                    countQuery.setParameter(paramNames[i], values[i]);
                    query.setParameter(paramNames[i], values[i]);
                }
            }
        }

        // 取得所有记录条数
        List countList = countQuery.list();
        if(!isContainDistinct)
        { 
            this.setCount(((Number) countList.get(0)).intValue());
        }else
        {
            this.setCount(countList.size());
        }
        
        // 获得分页的数据
        query.setFirstResult((page - 1) * pageSize);
        query.setMaxResults(pageSize);
        List list = query.list();

        // 关闭Session
        session.close();

        // 返回查询结果
        return list;
    }

    public int getCount()
    {
        return count;
    }

    public void setCount(int count)
    {
        this.count = count;
    }

    public SessionFactory getSessionFactory()
    {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory)
    {
        this.sessionFactory = sessionFactory;
    }
}